/**
 * 日期模块 - 借鉴Day.js和moment.js的设计理念
 * 提供日期时间处理、格式化、计算等功能
 */

// 常用日期格式正则
const _DATE_PATTERNS = {
  date: /^\d{4}-\d{2}-\d{2}$/,
  datetime: /^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/,
  time: /^\d{2}:\d{2}:\d{2}$/
};

// 中文星期映射
const WEEKDAYS_ZH = ['日', '一', '二', '三', '四', '五', '六'];
const WEEKDAYS_FULL_ZH = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];

// 中文月份映射
const MONTHS_ZH = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];

/**
 * 获取当前日期时间 格式"yyyy-MM-dd HH:mm:ss"
 * @returns {string} 当前日期时间
 */
export function getCurrentDateTime() {
  return formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss');
}

/**
 * 获取当前日期 格式"yyyy-MM-dd"
 * @returns {string} 当前日期
 */
export function getCurrentDate() {
  return formatDate(new Date(), 'YYYY-MM-DD');
}

/**
 * 获取当前时间 格式"HH:mm:ss"
 * @returns {string} 当前时间
 */
export function getCurrentTime() {
  return formatDate(new Date(), 'HH:mm:ss');
}

/**
 * 格式化日期
 * @param {Date|string|number} date 日期对象、字符串或时间戳
 * @param {string} format 格式字符串
 * @returns {string} 格式化后的日期字符串
 */
export function formatDate(date, format = 'YYYY-MM-DD') {
  const dateObj = parseDate(date);
  if (!dateObj || isNaN(dateObj.getTime())) return '';

  const year = dateObj.getFullYear();
  const month = dateObj.getMonth() + 1;
  const day = dateObj.getDate();
  const hour = dateObj.getHours();
  const minute = dateObj.getMinutes();
  const second = dateObj.getSeconds();
  const millisecond = dateObj.getMilliseconds();
  const weekDay = dateObj.getDay();

  const formatMap = {
    YYYY: year,
    YY: year.toString().slice(-2),
    MM: String(month).padStart(2, '0'),
    M: month,
    DD: String(day).padStart(2, '0'),
    D: day,
    HH: String(hour).padStart(2, '0'),
    H: hour,
    mm: String(minute).padStart(2, '0'),
    m: minute,
    ss: String(second).padStart(2, '0'),
    s: second,
    SSS: String(millisecond).padStart(3, '0'),
    dddd: WEEKDAYS_FULL_ZH[weekDay],
    dd: WEEKDAYS_ZH[weekDay],
    MMMM: MONTHS_ZH[month - 1]
  };

  let result = format;
  Object.keys(formatMap).forEach(key => {
    result = result.replace(new RegExp(key, 'g'), formatMap[key]);
  });

  return result;
}

/**
 * 解析日期
 * @param {Date|string|number} input 日期输入
 * @returns {Date|null} 日期对象
 */
export function parseDate(input) {
  if (!input) return null;

  if (input instanceof Date) {
    return new Date(input);
  }

  if (typeof input === 'number') {
    // 如果是10位时间戳，转换为13位
    const timestamp = input.toString().length === 10 ? input * 1000 : input;
    return new Date(timestamp);
  }

  if (typeof input === 'string') {
    // 尝试直接解析
    const date = new Date(input);
    if (!isNaN(date.getTime())) {
      return date;
    }

    // 尝试解析常见格式
    const formats = [
      /^(\d{4})-(\d{1,2})-(\d{1,2})$/,
      /^(\d{4})-(\d{1,2})-(\d{1,2})\s(\d{1,2}):(\d{1,2}):(\d{1,2})$/,
      /^(\d{4})\/(\d{1,2})\/(\d{1,2})$/,
      /^(\d{4})\.(\d{1,2})\.(\d{1,2})$/
    ];

    for (const format of formats) {
      const match = input.match(format);
      if (match) {
        const [, year, month, day, hour = 0, minute = 0, second = 0] = match;
        return new Date(year, month - 1, day, hour, minute, second);
      }
    }
  }

  return null;
}

/**
 * Unix时间戳转日期
 * @param {number} timestamp Unix时间戳（秒）
 * @returns {string} 日期字符串
 */
export function unixToDate(timestamp) {
  const date = new Date(timestamp * 1000);
  return formatDate(date, 'YYYY 年 M 月 D 日');
}

/**
 * Unix时间戳转日期时间
 * @param {number} timestamp Unix时间戳（秒）
 * @returns {string} 日期时间字符串
 */
export function unixToDateTime(timestamp) {
  const date = new Date(timestamp * 1000);
  return formatDate(date, 'YYYY 年 M 月 D 日 H:m');
}

/**
 * 时间字符串转Date对象
 * @param {string} dateString 时间字符串
 * @returns {Date} Date对象
 */
export function stringToDate(dateString) {
  if (typeof dateString !== 'string') return new Date();

  const parts = dateString.split(' ');
  const dateParts = parts[0].split('-');
  const timeParts = (parts[1] || '00:00:00').split(':');

  return new Date(
    parseInt(dateParts[0], 10),
    parseInt(dateParts[1], 10) - 1,
    parseInt(dateParts[2], 10),
    parseInt(timeParts[0], 10),
    parseInt(timeParts[1], 10),
    parseInt(timeParts[2], 10)
  );
}

/**
 * 指定时间后的时间
 * @param {number} milliseconds 毫秒数
 * @returns {string} 格式化后的时间
 */
export function getDateTimeAfter(milliseconds) {
  const date = new Date(new Date().getTime() + milliseconds);
  return formatDate(date, 'YYYYMMDDHHmmss');
}

/**
 * 计算年龄
 * @param {string|Date} birthday 生日
 * @returns {number} 年龄
 */
export function calculateAge(birthday) {
  const birthDate = parseDate(birthday);
  if (!birthDate) return 0;

  const today = new Date();
  const birthYear = birthDate.getFullYear();
  const birthMonth = birthDate.getMonth();
  const birthDay = birthDate.getDate();

  let age = today.getFullYear() - birthYear;

  // 检查是否还没到生日
  if (today.getMonth() < birthMonth ||
     (today.getMonth() === birthMonth && today.getDate() < birthDay)) {
    age--;
  }

  return Math.max(0, age);
}

/**
 * 计算两个日期的差值
 * @param {Date|string} date1 日期1
 * @param {Date|string} date2 日期2
 * @param {string} unit 单位 (days, hours, minutes, seconds)
 * @returns {number} 差值
 */
export function dateDiff(date1, date2, unit = 'days') {
  const d1 = parseDate(date1);
  const d2 = parseDate(date2);

  if (!d1 || !d2) return 0;

  const diffMs = Math.abs(d1.getTime() - d2.getTime());

  switch (unit) {
    case 'seconds':
      return Math.floor(diffMs / 1000);
    case 'minutes':
      return Math.floor(diffMs / (1000 * 60));
    case 'hours':
      return Math.floor(diffMs / (1000 * 60 * 60));
    case 'days':
      return Math.floor(diffMs / (1000 * 60 * 60 * 24));
    case 'weeks':
      return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 7));
    case 'months': {
      const months = (d1.getFullYear() - d2.getFullYear()) * 12 + (d1.getMonth() - d2.getMonth());
      return Math.abs(months);
    }
    case 'years':
      return Math.abs(d1.getFullYear() - d2.getFullYear());
    default:
      return Math.floor(diffMs / (1000 * 60 * 60 * 24));
  }
}

/**
 * 日期加法
 * @param {Date|string} date 日期
 * @param {number} amount 数量
 * @param {string} unit 单位
 * @returns {Date} 新日期
 */
export function dateAdd(date, amount, unit = 'days') {
  const dateObj = parseDate(date);
  if (!dateObj) return new Date();

  const result = new Date(dateObj);

  switch (unit) {
    case 'seconds':
      result.setSeconds(result.getSeconds() + amount);
      break;
    case 'minutes':
      result.setMinutes(result.getMinutes() + amount);
      break;
    case 'hours':
      result.setHours(result.getHours() + amount);
      break;
    case 'days':
      result.setDate(result.getDate() + amount);
      break;
    case 'weeks':
      result.setDate(result.getDate() + (amount * 7));
      break;
    case 'months':
      result.setMonth(result.getMonth() + amount);
      break;
    case 'years':
      result.setFullYear(result.getFullYear() + amount);
      break;
  }

  return result;
}

/**
 * 获取日期的开始时间
 * @param {Date|string} date 日期
 * @param {string} unit 单位 (day, week, month, year)
 * @returns {Date} 开始时间
 */
export function startOf(date, unit = 'day') {
  const dateObj = parseDate(date);
  if (!dateObj) return new Date();

  const result = new Date(dateObj);

  switch (unit) {
    case 'day':
      result.setHours(0, 0, 0, 0);
      break;
    case 'week':
      result.setHours(0, 0, 0, 0);
      result.setDate(result.getDate() - result.getDay());
      break;
    case 'month':
      result.setHours(0, 0, 0, 0);
      result.setDate(1);
      break;
    case 'year':
      result.setHours(0, 0, 0, 0);
      result.setMonth(0, 1);
      break;
  }

  return result;
}

/**
 * 获取日期的结束时间
 * @param {Date|string} date 日期
 * @param {string} unit 单位 (day, week, month, year)
 * @returns {Date} 结束时间
 */
export function endOf(date, unit = 'day') {
  const dateObj = parseDate(date);
  if (!dateObj) return new Date();

  const result = new Date(dateObj);

  switch (unit) {
    case 'day':
      result.setHours(23, 59, 59, 999);
      break;
    case 'week':
      result.setHours(23, 59, 59, 999);
      result.setDate(result.getDate() + (6 - result.getDay()));
      break;
    case 'month':
      result.setHours(23, 59, 59, 999);
      result.setMonth(result.getMonth() + 1, 0);
      break;
    case 'year':
      result.setHours(23, 59, 59, 999);
      result.setMonth(11, 31);
      break;
  }

  return result;
}

/**
 * 判断是否为闰年
 * @param {number} year 年份
 * @returns {boolean} 是否为闰年
 */
export function isLeapYear(year) {
  if (typeof year !== 'number') return false;
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}

/**
 * 获取月份的天数
 * @param {number} year 年份
 * @param {number} month 月份 (1-12)
 * @returns {number} 天数
 */
export function getDaysInMonth(year, month) {
  if (typeof year !== 'number' || typeof month !== 'number') return 0;
  return new Date(year, month, 0).getDate();
}

/**
 * 判断日期是否有效
 * @param {Date|string} date 日期
 * @returns {boolean} 是否有效
 */
export function isValidDate(date) {
  const dateObj = parseDate(date);
  return dateObj instanceof Date && !isNaN(dateObj.getTime());
}

/**
 * 格式化相对时间（几分钟前、几小时前等）
 * @param {Date|string} date 日期
 * @returns {string} 相对时间描述
 */
export function timeAgo(date) {
  const dateObj = parseDate(date);
  if (!dateObj) return '';

  const now = new Date();
  const diff = now.getTime() - dateObj.getTime();
  const seconds = Math.floor(diff / 1000);
  const minutes = Math.floor(seconds / 60);
  const hours = Math.floor(minutes / 60);
  const days = Math.floor(hours / 24);
  const months = Math.floor(days / 30);
  const years = Math.floor(days / 365);

  if (seconds < 60) {
    return '刚刚';
  } else if (minutes < 60) {
    return `${minutes}分钟前`;
  } else if (hours < 24) {
    return `${hours}小时前`;
  } else if (days < 30) {
    return `${days}天前`;
  } else if (months < 12) {
    return `${months}个月前`;
  } else {
    return `${years}年前`;
  }
}

/**
 * 获取星座
 * @param {number} month 月份
 * @param {number} day 日期
 * @returns {string} 星座名称
 */
export function getConstellation(month, day) {
  if (typeof month !== 'number' || typeof day !== 'number') return '';
  if (month < 1 || month > 12 || day < 1 || day > 31) return '';

  const zodiacData = [
    { name: '水瓶座', start: [1, 20], end: [2, 18] },
    { name: '双鱼座', start: [2, 19], end: [3, 20] },
    { name: '白羊座', start: [3, 21], end: [4, 19] },
    { name: '金牛座', start: [4, 20], end: [5, 20] },
    { name: '双子座', start: [5, 21], end: [6, 21] },
    { name: '巨蟹座', start: [6, 22], end: [7, 22] },
    { name: '狮子座', start: [7, 23], end: [8, 22] },
    { name: '处女座', start: [8, 23], end: [9, 22] },
    { name: '天秤座', start: [9, 23], end: [10, 23] },
    { name: '天蝎座', start: [10, 24], end: [11, 22] },
    { name: '射手座', start: [11, 23], end: [12, 21] },
    { name: '摩羯座', start: [12, 22], end: [1, 19] }
  ];

  for (const zodiac of zodiacData) {
    const [startMonth, startDay] = zodiac.start;
    const [endMonth, endDay] = zodiac.end;

    if (startMonth === endMonth) {
      // 同月内的星座
      if (month === startMonth && day >= startDay && day <= endDay) {
        return zodiac.name;
      }
    } else {
      // 跨月的星座
      if ((month === startMonth && day >= startDay) ||
          (month === endMonth && day <= endDay)) {
        return zodiac.name;
      }
    }
  }

  return '';
}

/**
 * 获取生肖
 * @param {Date|string} date 日期
 * @returns {string} 生肖名称
 */
export function getChineseZodiac(date) {
  const dateObj = parseDate(date);
  if (!dateObj) return '';

  const year = dateObj.getFullYear();
  const animals = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'];

  // 1900年是鼠年
  const index = (year - 1900) % 12;
  return animals[index];
}

/**
 * 格式化日期（别名）
 * @param {Date|string|number} date 日期
 * @param {string} format 格式字符串
 * @returns {string} 格式化后的日期字符串
 */
export function format(date, format = 'YYYY-MM-DD') {
  return formatDate(date, format);
}

/**
 * 解析日期字符串（别名）
 * @param {string} dateString 日期字符串
 * @returns {Date|null} 日期对象
 */
export function parse(dateString) {
  return parseDate(dateString);
}

/**
 * 日期加法（别名）
 * @param {Date|string} date 日期
 * @param {number} amount 数量
 * @param {string} unit 单位
 * @returns {Date} 新日期
 */
export function add(date, amount, unit = 'day') {
  return dateAdd(date, amount, unit);
}

/**
 * 日期减法
 * @param {Date|string} date 日期
 * @param {number} amount 数量
 * @param {string} unit 单位
 * @returns {Date} 新日期
 */
export function subtract(date, amount, unit = 'day') {
  return dateAdd(date, -amount, unit);
}

/**
 * 计算日期差值（别名）
 * @param {Date|string} date1 日期1
 * @param {Date|string} date2 日期2
 * @param {string} unit 单位
 * @returns {number} 差值
 */
export function diff(date1, date2, unit = 'days') {
  return dateDiff(date1, date2, unit);
}

/**
 * 验证日期有效性（别名）
 * @param {Date|string} date 日期
 * @returns {boolean} 是否有效
 */
export function isValid(date) {
  return isValidDate(date);
}

/**
 * 获取季度
 * @param {Date|string} date 日期
 * @returns {number} 季度 (1-4)
 */
export function getQuarter(date) {
  const dateObj = parseDate(date);
  if (!dateObj) return 1;

  const month = dateObj.getMonth() + 1;
  return Math.ceil(month / 3);
}

/**
 * 获取年中的第几周
 * @param {Date|string} date 日期
 * @returns {number} 周数
 */
export function getWeekOfYear(date) {
  const dateObj = parseDate(date);
  if (!dateObj) return 1;

  const startOfYear = new Date(dateObj.getFullYear(), 0, 1);
  const pastDaysOfYear = (dateObj - startOfYear) / 86400000;
  return Math.ceil((pastDaysOfYear + startOfYear.getDay() + 1) / 7);
}

/**
 * 判断是否为同一天
 * @param {Date|string} date1 日期1
 * @param {Date|string} date2 日期2
 * @returns {boolean} 是否为同一天
 */
export function isSameDay(date1, date2) {
  const d1 = parseDate(date1);
  const d2 = parseDate(date2);

  if (!d1 || !d2) return false;

  return d1.getFullYear() === d2.getFullYear() &&
         d1.getMonth() === d2.getMonth() &&
         d1.getDate() === d2.getDate();
}

/**
 * 判断是否为今天
 * @param {Date|string} date 日期
 * @returns {boolean} 是否为今天
 */
export function isToday(date) {
  return isSameDay(date, new Date());
}

/**
 * 获取生肖
 * @param {number} year 年份
 * @returns {string} 生肖
 */
export function getZodiac(year) {
  if (typeof year !== 'number' || year < 1900) return '';

  const animals = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'];
  // 1900年是鼠年
  const index = (year - 1900) % 12;
  return animals[index];
}

/**
 * 转换为相对时间（别名）
 * @param {Date|string} date 日期
 * @returns {string} 相对时间描述
 */
export function toRelativeTime(date) {
  return timeAgo(date);
}
